package com.usbserial.core;

import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;

import com.usbserial.driver.DriverFactory;
import com.usbserial.driver.DriverType;
import com.usbserial.driver.UsbSerialDriver;
import com.usbserial.exception.PermissionDeniedException;
import com.usbserial.exception.UsbSerialException;

import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Entry point into the Android-native USB serial library.
 */
public class UsbSerialManager implements Closeable {

    private final Context context;
    private final UsbManager usbManager;
    private final UsbPermissionHandler permissionHandler;

    public UsbSerialManager(Context context) {
        this.context = context.getApplicationContext();
        this.usbManager = (UsbManager) this.context.getSystemService(Context.USB_SERVICE);
        this.permissionHandler = new UsbPermissionHandler(this.context, usbManager);
    }

    /**
     * Returns a snapshot of connected USB serial capable devices.
     */
    public List<UsbSerialDeviceInfo> listDevices() {
        Map<String, UsbDevice> devices = usbManager.getDeviceList();
        if (devices == null || devices.isEmpty()) {
            return Collections.emptyList();
        }
        List<UsbSerialDeviceInfo> result = new ArrayList<>(devices.size());
        for (UsbDevice device : devices.values()) {
            result.add(new UsbSerialDeviceInfo(device, DriverType.AUTO));
        }
        return result;
    }

    public boolean hasPermission(UsbDevice device) {
        return permissionHandler.hasPermission(device);
    }

    public void requestPermission(UsbDevice device, UsbPermissionCallback callback) {
        permissionHandler.requestPermission(device, callback);
    }

    /**
     * Opens the specified device returning a SerialPort wrapper. Caller is responsible for closing it.
     */
    public SerialPort openPort(UsbSerialDeviceInfo deviceInfo, SerialConfig config) throws UsbSerialException {
        return openPort(deviceInfo, config, -1);
    }

    public SerialPort openPort(UsbSerialDeviceInfo deviceInfo, SerialConfig config, int interfaceIndex) throws UsbSerialException {
        UsbDevice device = deviceInfo.getUsbDevice();
        UsbDeviceConnection connection = usbManager.openDevice(device);
        if (connection == null) {
            throw new PermissionDeniedException("Unable to obtain UsbDeviceConnection. Missing permission?");
        }
        UsbSerialDriver driver = DriverFactory.createDriver(device, connection, deviceInfo.getDriverType(), interfaceIndex);
        return new SerialPort(connection, driver, config);
    }

    @Override
    public void close() throws IOException {
        permissionHandler.dispose();
    }
}
